package com.corgi.mybatis.util;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

/**
 * @title: AesUtil
 * @description:
 * @author: dengmiao
 * @create: 2019-10-28 16:06
 **/
public class AesUtil {

    private static final String charsetName = "UTF-8";

    /**
     * AES CBC 加密
     * @param message 需要加密的字符串
     * @param key   密匙
     * @param iv    IV，需要和key长度相同
     * @return  返回加密后密文，编码为base64
     */
    public static String encryptCBC(String message, String key, String iv) {
        final String cipherMode = "AES/CBC/PKCS5Padding";
        try {
            byte[] content = new byte[0];
            content = message.getBytes(charsetName);
            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
            //
            byte[] ivByte = iv.getBytes(charsetName);
            IvParameterSpec ivSpec = new IvParameterSpec(ivByte);

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] data = cipher.doFinal(content);
            final String result = RsaUtil.byte2Base64(data);
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }

        return null;
    }
    /**
     * AES CBC 解密
     * @param messageBase64 密文，base64编码
     * @param key   密匙，和加密时相同
     * @param iv    IV，需要和key长度相同
     * @return  解密后数据
     */
    public static String decryptCBC(String messageBase64, String key, String iv) {
        final String cipherMode = "AES/CBC/PKCS5Padding";
        try {
            byte[] messageByte = RsaUtil.base642Byte(messageBase64);

            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
            //
            byte[] ivByte = iv.getBytes(charsetName);
            IvParameterSpec ivSpec = new IvParameterSpec(ivByte);

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] content = cipher.doFinal(messageByte);
            String result = new String(content, charsetName);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * AES ECB 加密
     * @param message 需要加密的字符串
     * @param key   密匙
     * @return  返回加密后密文，编码为base64
     */
    public static String encryptECB(String message, String key) {
        final String cipherMode = "AES/ECB/PKCS5Padding";
        try {
            byte[] content = new byte[0];
            content = message.getBytes(charsetName);
            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
            byte[] data = cipher.doFinal(content);
            final String result = RsaUtil.byte2Base64(data);
            return result;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }

        return null;
    }
    /**
     * AES ECB 解密
     * @param messageBase64 密文，base64编码
     * @param key   密匙，和加密时相同
     * @return  解密后数据
     */
    public static String decryptECB(String messageBase64, String key) {
        final String cipherMode = "AES/ECB/PKCS5Padding";
        try {
            byte[] messageByte = RsaUtil.base642Byte(messageBase64);
            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.DECRYPT_MODE, keySpec);
            byte[] content = cipher.doFinal(messageByte);
            String result = new String(content, charsetName);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     *
     * @param content
     * @param key
     * @param iv 初始化向量参数，AES 为16bytes. DES 为8bytes.
     * @return
     * @throws Exception
     */
    public static String encrypt(String content, String key, String iv) {
        try {
            //两个参数，第一个为私钥字节数组， 第二个为加密方式 AES或者DES
            Key keySpec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, keySpec,ivSpec);
            //Cipher cipher = AesUtil.generateCipher(Cipher.ENCRYPT_MODE,"1234567890123456".getBytes(),"1234567890123456".getBytes());
            byte[] byteResult = cipher.doFinal(content.getBytes());
            /*StringBuffer sb = new StringBuffer();
            for (int i = 0; i < byteResult.length; i++) {
                String hex = Integer.toHexString(byteResult[i] & 0xFF);
                if (hex.length() == 1) {
                    hex = '0' + hex;
                }
                sb.append(hex.toUpperCase());
            }*/
            return DecimalUtil.binaryToHexString(byteResult);
            //return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String messageBase64, String key, String iv) {
        final String cipherMode = "AES/CBC/PKCS5Padding";
        try {
            byte[] messageByte = DecimalUtil.hexStringToBinary(messageBase64);

            //
            byte[] keyByte = key.getBytes(charsetName);
            SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
            //
            byte[] ivByte = iv.getBytes(charsetName);
            IvParameterSpec ivSpec = new IvParameterSpec(ivByte);

            Cipher cipher = Cipher.getInstance(cipherMode);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] content = cipher.doFinal(messageByte);
            String result = new String(content, charsetName);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 测试
     */
    public static void main(String[] args) {
        String key = "1234567890123456";
        String iv = "1234567890000000";
        String msg = "这是一个测试这是一个测试这是一个测试";
        {
            String encrypt = AesUtil.encryptCBC(msg, key, iv);
            System.out.println(encrypt);
            String decryptStr = AesUtil.decryptCBC(encrypt, key, iv);
            System.out.println(decryptStr);
        }
        {
            String encrypt = AesUtil.encryptECB(msg, key);
            System.out.println(encrypt);
            String decryptStr = AesUtil.decryptECB(encrypt, key);
            System.out.println(decryptStr);
        }
        {
            String encrypt = "+Q6VtKmxsbpCovly0yafPN0KQeBhWN9fQqaBN5F/JKoCJPheNARZqNUkiSmaxHA8ZstMtx+Cf0cfnW9bGVrAhQ==";
            System.out.println(AesUtil.decryptCBC(encrypt, key, iv));
            System.out.println("----------");
            String enc = encrypt("你好, 世界", key, iv);
            System.out.println(enc);
            String dec = decrypt(enc, key, iv);
            System.out.println(dec);
        }
    }
}
